#include <opencv2/opencv.hpp>
#include <dlib/opencv.h>
#include <dlib/image_processing/frontal_face_detector.h>
#include <dlib/image_processing.h>
#include <dlib/image_io.h>
#include <nadjieb/mjpeg_streamer.hpp>
#include <sys/stat.h> // 用于创建目录
#include <chrono>
#include <iomanip>

#define INTV 10 // 间隔多少帧做一次人脸识别
#define SAVE_INTERVAL 5 // 每检测到5次人脸保存一张图片

using namespace std;
using namespace dlib;

// 创建目录函数
bool createDirectory(const string& path) {
    struct stat st;
    if (stat(path.c_str(), &st) == -1) {
        mkdir(path.c_str(), 0755);
        return true;
    }
    return false;
}

int main() {
    int count = 0;
    int save_count = 0;
    
    // 创建保存目录
    string save_dir = "/home/ubuntu/pictures";
    createDirectory(save_dir);

    // 创建VideoCapture对象，参数0表示打开默认摄像头
    cv::VideoCapture cap(0);
    if (!cap.isOpened()) {
        cerr << "无法打开摄像头" << endl;
        return -1;
    }

    // 初始化MJPEG流服务器
    nadjieb::MJPEGStreamer streamer;
    // 设置HTTP服务器端口
    streamer.start(8080);
    
    // JPEG编码参数
    std::vector<int> params = {cv::IMWRITE_JPEG_QUALITY, 90};

    // 初始化人脸检测器
    frontal_face_detector detector = get_frontal_face_detector();

    // 加载人脸特征点检测器
    shape_predictor sp;
    deserialize("/home/ubuntu/practice/model/shape_predictor_68_face_landmarks.dat") >> sp;

    // 主循环，持续捕获和显示视频帧
    while (true) {
        // 创建一个Mat对象来存储当前帧
        cv::Mat frame; 
        // 从摄像头捕获一帧图像
        cap >> frame;
        // 检查捕获的帧是否为空，如果为空则退出循环
        if (frame.empty()) {
            cerr << "frame not grabbed\n";
            break;
        }

        // 将OpenCV Mat转换为dlib格式
        cv_image<bgr_pixel> dlib_img(frame);

        // 每INTV帧检测一次人脸
        if (count % INTV == 0) {
            // 调用人脸检测，detector，返回人脸矩形框列表
            std::vector<rectangle> faces = detector(dlib_img);
            // 显示结果：打印人脸数量和每个矩形框的四个点
            cout << "检测到人脸数量: " << faces.size() << endl;
            
            // 在OpenCV图像上绘制人脸矩形框
            for (const auto& face : faces) {
                cout << "人脸矩形框: 左上角(" << face.left() << ", " << face.top()
                     << "), 右下角(" << face.right() << ", " << face.bottom() << ")" << endl;
                
                cv::rectangle(frame, cv::Point(face.left(), face.top()),
                            cv::Point(face.right(), face.bottom()),
                            cv::Scalar(0, 255, 0), 2);

                // 每5次检测保存一次对齐后的人脸
                if (save_count % SAVE_INTERVAL == 0) 
                {
                    try 
                    {
                        // 提取人脸特征点
                        auto shape = sp(dlib_img, face);
                        
                        // 对齐人脸
                        matrix<rgb_pixel> face_chip;
                        extract_image_chip(dlib_img, get_face_chip_details(shape, 150, 0.25), face_chip);
                        
                        // 生成带时间戳的文件名
                        auto now = chrono::system_clock::now();
                        auto now_c = chrono::system_clock::to_time_t(now);
                        stringstream ss;
                        ss << save_dir << "/aligned_face_" << put_time(localtime(&now_c), "%Y%m%d_%H%M%S") << ".jpg";
                        
                        // 保存对齐后的人脸
                        save_jpeg(face_chip, ss.str());
                        cout << "已保存对齐人脸到: " << ss.str() << endl;
                    } 
                    catch (exception& e) 
                    {
                        cerr << "人脸对齐失败: " << e.what() << endl;
                    }
                }
                save_count++;
            }
        }

        // 增加帧计数
        count++;

        // 将帧编码为JPEG并推送到流
        std::vector<uchar> buff_bgr;
        cv::imencode(".jpg", frame, buff_bgr, params);
        streamer.publish("/bgr", std::string(buff_bgr.begin(), buff_bgr.end()));

        // 添加小的延迟
        cv::waitKey(30);
    }

    // 停止流服务器
    streamer.stop();
    return 0;
}